# -*- coding: utf-8 -*-
"""GENERATOR KKTP — Kriteria Ketercapaian Tujuan Pembelajaran
===========================================================================

Membuat berkas KKTP (DOCX) yang sinkron dengan ATP dan RPM:

  * Elemen dan Capaian Pembelajaran disalin dari dokumen rujukan resmi
    (Kepkabadan Kemendikdasmen No. 046/H/KR/2025) melalui cp_db.json;
  * Tujuan Pembelajaran memakai rumusan yang sama persis dengan ATP dan RPM,
    karena ketiganya memanggil mesin yang sama (atp.susun_rencana);
  * baris "Capaian Pembelajaran" pada identitas terisi otomatis sesuai mata
    pelajaran dan lingkup yang dipilih;
  * kriteria empat interval (0-74 / 75-79 / 80-91 / 92-100) disusun dari kata
    kerja dan pokok materi tiap Tujuan Pembelajaran;
  * Kepala Sekolah sudah tetap, Guru Mata Pelajaran diisi melalui form.

Lingkup:
  tahun    — satu berkas per semester aktif pada kelas tersebut
  semester — satu semester saja (1 berkas)
  elemen   — satu Elemen/CP saja (1 berkas)

Contoh:
  py atpgen/kktp.py --form
  py atpgen/kktp.py --mapel "bahasa indonesia" --kelas X --jp 4 --jpp 2 \
                    --lingkup semester --semester ganjil --penyusun "Eng, S.Pd."
"""
from __future__ import print_function

import argparse
import os
import re
import sys

import docx
from docx.enum.section import WD_ORIENT
from docx.enum.table import WD_TABLE_ALIGNMENT
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.shared import Cm, Pt

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from atp import (BASE_OUT, FONT, KELAS_FASE, KEPALA_NAMA, KEPALA_NPA, TITIK,
                 blok_ttd, cari_mapel, kecil_awal, load_db, npa_teks,
                 semester_aktif, set_cell, shade, style_run, susun_rencana)
from rpm import (bersih_bullet, daftar_tp, detail_aktif, karakter_mapel,
                 pokok_tp, rapikan_tp, ringkas, topik_utama, _kata_kerja)

LEBAR = [1.2, 4.6, 7.0, 4.3, 4.3, 4.3, 4.3]
JUDUL_INTERVAL = ["Perlu Bimbingan", "Cukup", "Baik", "Sangat Baik"]
KET_INTERVAL = [
    "0-74%\n(Belum mencapai, remedial di seluruh bagian)",
    "75-79%\n(Belum mencapai ketuntasan, remedial di bagian yang diperlukan)",
    "80-91%\n(Sudah mencapai ketuntasan, tidak perlu remedial)",
    "92-100%\n(Sudah mencapai ketuntasan, perlu pengayaan atau tantangan lebih)",
]

# Penyebutan mutu kerja menurut watak mata pelajaran.
MUTU = {
    "kejuruan": ("sesuai prosedur kerja (SOP) dan ketentuan K3",
                 "ketepatan langkah kerja dan keselamatan kerja"),
    "seni": ("sesuai kaidah dan nilai estetika karya",
             "ketepatan teknik serta penghayatan karya"),
    "bahasa": ("sesuai kaidah kebahasaan yang tepat",
               "ketepatan struktur dan pilihan kata"),
    "umum": ("sesuai kaidah dan konsep yang berlaku",
             "ketepatan konsep dan penalaran"),
}


# ============================================================================
# 1. KRITERIA EMPAT INTERVAL
# ============================================================================


def _inti_tp(tp):
    """Pisahkan kata kerja dan pokok materi dari satu rumusan TP."""
    x = re.sub(r"^\s*\d+\.\s*", "", (tp or "").strip())
    x = re.sub(r"^Murid mampu\s+", "", x, flags=re.I).strip().rstrip(".")
    kk = _kata_kerja(x) or "memahami"
    pokok = pokok_tp(tp)
    pokok = re.sub(r"\s+", " ", pokok).strip().rstrip(".")
    if not pokok or len(pokok) < 6:
        pokok = ringkas(x, 100)
    return kk, kecil_awal(pokok), kecil_awal(x)


def kriteria(tp, watak="umum"):
    """Empat deskriptor kriteria ketercapaian untuk satu Tujuan Pembelajaran.

    Deskriptor disusun dari kata kerja dan pokok materi TP itu sendiri, jadi
    tidak ada rumusan yang mengambang atau tidak berkaitan dengan materinya.
    """
    kk, pokok, penuh = _inti_tp(tp)
    mutu, fokus = MUTU.get(watak, MUTU["umum"])
    return [
        ("Murid belum mampu %s %s. Pemahaman masih terbatas dan pekerjaan "
         "belum selesai atau banyak keliru, sehingga masih memerlukan bimbingan "
         "penuh dengan contoh terurai. Remedial diberikan pada seluruh bagian."
         % (kk, pokok)),
        ("Murid mampu %s %s hanya sebagian atau masih dengan bantuan dan "
         "petunjuk guru. Masih terdapat kekeliruan pada %s, sehingga remedial "
         "diberikan pada bagian yang diperlukan saja."
         % (kk, pokok, fokus)),
        ("Murid mampu %s %s secara tepat dan mandiri %s. Hasil kerja sudah "
         "memenuhi kriteria ketuntasan sehingga tidak perlu remedial."
         % (kk, pokok, mutu)),
        ("Murid mampu %s %s secara tepat, mandiri, dan runtut %s, mampu "
         "menjelaskan alasan setiap langkahnya, serta dapat membimbing teman. "
         "Layak diberi pengayaan berupa kasus atau tugas yang lebih menantang."
         % (kk, pokok, mutu)),
    ]


# ============================================================================
# 2. PENYUSUN ISI KKTP
# ============================================================================


def baris_kktp(sumber, watak):
    """Susun baris tabel KKTP: satu baris untuk satu Tujuan Pembelajaran."""
    baris = []
    for e in daftar_tp(sumber):
        tp = re.sub(r"^\s*\d+\.\s*", "", e["tp"]).strip()
        baris.append({"elemen": topik_utama(e["elemen"]), "tp": tp,
                      "kriteria": kriteria(e["tp"], watak)})
    return baris


def teks_cp(sumber):
    """Isi baris "Capaian Pembelajaran" pada identitas, otomatis sesuai mapel."""
    pasang = []
    for d in sumber:
        nama = topik_utama(d["elemen"])
        if nama not in [x[0] for x in pasang]:
            pasang.append((nama, re.sub(r"\s+", " ", d["cp"]).strip()))
    if len(pasang) == 1:
        return [pasang[0][1]]
    return ["%d. %s: %s" % (i + 1, n, c) for i, (n, c) in enumerate(pasang)]


# ============================================================================
# 3. PENULIS DOKUMEN
# ============================================================================


def tulis_kktp(meta, sumber, id_data, out_path, label):
    doc = docx.Document()
    sec = doc.sections[0]
    sec.orientation = WD_ORIENT.LANDSCAPE
    sec.page_width, sec.page_height = Cm(33.0), Cm(21.0)
    sec.left_margin = sec.right_margin = Cm(1.5)
    sec.top_margin = sec.bottom_margin = Cm(1.5)
    doc.styles["Normal"].font.name = FONT
    doc.styles["Normal"].font.size = Pt(10)

    def para(t, bold=False, size=10, align=WD_ALIGN_PARAGRAPH.LEFT):
        p = doc.add_paragraph()
        p.alignment = align
        p.paragraph_format.space_after = Pt(0)
        style_run(p.add_run(t), size, bold)
        return p

    para("KRITERIA KETERCAPAIAN TUJUAN PEMBELAJARAN (KKTP)", True, 12,
         WD_ALIGN_PARAGRAPH.CENTER)
    para("TAHUN PELAJARAN %s" % meta["tahun"], True, 12, WD_ALIGN_PARAGRAPH.CENTER)
    para("")
    para("Satuan Pendidikan\t: %s" % meta["sekolah"])
    para("Mata Pelajaran\t\t: %s" % meta["mapel"])
    para("Kelas / Konsentrasi Keahlian\t: %s / %s"
         % (id_data["rombel"], id_data["konsentrasi"]))
    para("Fase / Semester\t\t: Fase %s / %s" % (meta["fase"], label))
    para("Tahun Pelajaran\t\t: %s" % meta["tahun"])
    para("")
    baris_cp = teks_cp(sumber)
    para("Capaian Pembelajaran:", True)
    for x in baris_cp:
        p = para(x, False, 10, WD_ALIGN_PARAGRAPH.JUSTIFY)
        p.paragraph_format.left_indent = Cm(0.5)
    para("")

    data = baris_kktp(sumber, meta["watak"])
    t = doc.add_table(rows=3 + len(data), cols=7)
    t.style = "Table Grid"
    t.alignment = WD_TABLE_ALIGNMENT.CENTER

    # --- kepala tabel: No / Elemen / TP digabung tiga baris, "Interval" melebar
    for j, h in enumerate(["No", "Elemen", "Tujuan Pembelajaran"]):
        c = t.cell(0, j).merge(t.cell(2, j))
        set_cell(c, h, WD_ALIGN_PARAGRAPH.CENTER, True, 10)
        shade(c, "D9E2F3")
    ci = t.cell(0, 3).merge(t.cell(0, 6))
    set_cell(ci, "Interval", WD_ALIGN_PARAGRAPH.CENTER, True, 10)
    shade(ci, "D9E2F3")
    for k in range(4):
        c = t.cell(1, 3 + k)
        set_cell(c, JUDUL_INTERVAL[k], WD_ALIGN_PARAGRAPH.CENTER, True, 9)
        shade(c, "D9E2F3")
        c = t.cell(2, 3 + k)
        set_cell(c, KET_INTERVAL[k], WD_ALIGN_PARAGRAPH.CENTER, False, 8)
        shade(c, "F2F2F2")

    # --- isi tabel
    for i, b in enumerate(data):
        r = t.rows[3 + i]
        set_cell(r.cells[0], str(i + 1), WD_ALIGN_PARAGRAPH.CENTER, False, 9)
        set_cell(r.cells[1], b["elemen"], WD_ALIGN_PARAGRAPH.LEFT, False, 9)
        set_cell(r.cells[2], b["tp"], WD_ALIGN_PARAGRAPH.JUSTIFY, False, 9)
        for k in range(4):
            set_cell(r.cells[3 + k], b["kriteria"][k], WD_ALIGN_PARAGRAPH.JUSTIFY,
                     False, 8)

    t.autofit = False
    for r in t.rows:
        for j, w in enumerate(LEBAR):
            if j < len(r.cells):
                r.cells[j].width = Cm(w)

    para("")
    para("Catatan:", True, 9)
    para("1. Elemen dan Capaian Pembelajaran disalin sesuai Kepkabadan "
         "Kemendikdasmen No. 046/H/KR/2025, Lampiran %s (%s)."
         % (meta["lampiran"], meta["kode"]), size=9)
    para("2. Rumusan Tujuan Pembelajaran sama dengan yang tercantum pada ATP "
         "dan RPM mata pelajaran ini.", size=9)
    para("3. Ketuntasan dicapai pada interval 80-91% (Baik). Murid pada interval "
         "0-74% dan 75-79% mengikuti remedial sesuai bagian yang belum tercapai.",
         size=9)
    para("")
    para("")
    blok_ttd(doc, id_data["kota"], id_data.get("penyusun"), id_data.get("npa"),
             meta["sekolah"], lebar=(15.0, 15.0))

    doc.save(out_path)
    return out_path, len(data)


# ============================================================================
# 4. MESIN UTAMA
# ============================================================================


def nama_berkas(meta, label):
    m = re.sub(r"[^A-Za-z0-9 ]", " ", meta["mapel"]).strip().upper()
    m = re.sub(r"\s+", " ", m)
    lb = re.sub(r"[^A-Za-z0-9 ]", " ", label).strip().upper()
    lb = re.sub(r"\s+", " ", lb)
    return "KKTP - %s - KELAS %s - %s.docx" % (m, meta["kelas"], lb)


def generate_kktp(mapel, jp, kelas=None, fase=None, mg=22, mn=15, menit=45,
                  jpp=None, lingkup="semester", semester=None, elemen=None,
                  sekolah="SMKS PGRI 2 Jambi", tahun="2026/2027",
                  penyusun=None, npa=None, kota="Jambi", rombel=None,
                  konsentrasi="Teknik Sepeda Motor", elemen_kelas=None,
                  out_dir=None, diam=False):
    db = load_db()
    calon = cari_mapel(db, mapel, fase=fase)
    if not calon:
        print("\u274c Mata pelajaran '%s' tidak ditemukan pada basis data CP." % mapel)
        sys.exit(1)
    s = calon[0]

    kelas = kelas or "X"
    fase = fase or KELAS_FASE.get(kelas, "E")
    r = susun_rencana(s["nama_asli"], jp, kelas=kelas, fase=fase, mg=mg, mn=mn,
                      menit=menit, jpp=jpp, sekolah=sekolah, tahun=tahun,
                      elemen_kelas=elemen_kelas, penyusun=penyusun, npa=npa,
                      kota=kota)
    meta = dict(r["meta"])
    meta["watak"] = karakter_mapel(s, r["elemen"][0]["elemen"] if r["elemen"] else "",
                                   r["elemen"][0]["cp"] if r["elemen"] else "")
    id_data = {"penyusun": penyusun, "npa": npa, "kota": kota,
               "rombel": rombel or kelas, "konsentrasi": konsentrasi,
               "kepala": KEPALA_NAMA, "kepala_npa": KEPALA_NPA}

    lingkup = (lingkup or "semester").lower().strip()
    tugas = []
    if lingkup in ("elemen", "cp", "1elemen"):
        sumber = detail_aktif(r, semester)
        if elemen not in (None, "", 0, "0"):
            saring = [d for d in sumber if d["urut_kelas"] == int(elemen)]
            if not saring:
                print("\u274c Elemen/CP nomor %s tidak ada pada lingkup tersebut." % elemen)
                for d in sumber:
                    print("     %d. %s" % (d["urut_kelas"], topik_utama(d["elemen"])))
                sys.exit(1)
            sumber = saring
        for d in sumber:
            tugas.append(([d], "%s - ELEMEN %d" % (d["label_semester"], d["urut_kelas"])))
    elif lingkup in ("semester", "1semester", "1"):
        sumber = detail_aktif(r, semester)
        if not sumber:
            print("\u274c Semester '%s' tidak tersedia untuk Kelas %s." % (semester, kelas))
            sys.exit(1)
        tugas.append((sumber, sumber[0]["label_semester"]))
    else:
        for a in semester_aktif(fase, kelas):
            sumber = detail_aktif(r, str(a[0]))
            if sumber:
                tugas.append((sumber, sumber[0]["label_semester"]))

    if out_dir is None:
        m = re.sub(r"[^A-Za-z0-9 ]", " ", meta["mapel"]).strip().upper()
        out_dir = os.path.join(BASE_OUT, "KKTP %s - KELAS %s FASE %s"
                               % (re.sub(r"\s+", " ", m), kelas, fase))
    out_dir = os.path.abspath(out_dir)
    if not os.path.isdir(out_dir):
        os.makedirs(out_dir)

    if not diam:
        print("")
        print("   Mapel        : %s  (Lampiran %s, %s)"
              % (meta["mapel"], meta["lampiran"], meta["kode"]))
        print("   Fase / Kelas : %s / %s" % (fase, kelas))
        print("   Guru Mapel   : %s  (%s)"
              % ((penyusun or "").strip() or TITIK, npa_teks(npa)))
        print("   Kepala       : %s  (%s)" % (KEPALA_NAMA, KEPALA_NPA))
        print("")

    hasil = []
    for sumber, label in tugas:
        path = os.path.join(out_dir, nama_berkas(meta, label))
        path, n = tulis_kktp(meta, sumber, id_data, path, label)
        hasil.append((path, n, label))
        if not diam:
            print("   \u2022 [%s] %d Elemen/CP | %d Tujuan Pembelajaran"
                  % (label, len(set(d["urut_kelas"] for d in sumber)), n))
            print("       %s" % os.path.basename(path))

    if not diam:
        print("")
        print("   \U0001F4C1 TERSIMPAN DI FOLDER:")
        print("   %s" % out_dir)
        print("")
    return hasil


# ============================================================================
# 5. FORM
# ============================================================================


def tanya(teks, bawaan=""):
    x = input("%s [%s]: " % (teks, bawaan)).strip()
    return x or bawaan


def mode_form(bawaan=None):
    bawaan = bawaan or {}
    print("")
    print("=" * 74)
    print("  GENERATOR KKTP \u2014 KRITERIA KETERCAPAIAN TUJUAN PEMBELAJARAN")
    print("=" * 74)

    db = load_db()
    while True:
        mapel = tanya("[1] Mata Pelajaran", bawaan.get("mapel", ""))
        calon = cari_mapel(db, mapel)
        if calon:
            break
        print("    \u274c Tidak ditemukan. Coba kata kunci lain.")
    if len(calon) > 1:
        print("    Ditemukan beberapa mata pelajaran:")
        for i, x in enumerate(calon[:9], 1):
            print("      %d. %s" % (i, x["nama_asli"]))
        no = tanya("    Pilih nomor", "1")
        s = calon[int(no) - 1 if no.isdigit() else 0]
    else:
        s = calon[0]
    print("    \u2713 %s (Lampiran %s, %s)" % (s["nama_asli"], s["lampiran"], s["kode"]))

    kelas = tanya("[2] Kelas (X / XI / XII)", bawaan.get("kelas", "X")).upper()
    fase = KELAS_FASE.get(kelas, "E")
    jp = int(tanya("[3] JP dalam 1 minggu", str(bawaan.get("jp", 2))))
    jpp = int(tanya("[4] JP dalam 1x pertemuan", str(bawaan.get("jpp", jp))))
    print("[5] Jumlah minggu efektif")
    mg = int(tanya("      - Semester Ganjil", str(bawaan.get("mg", 22))))
    mn = int(tanya("      - Semester Genap", str(bawaan.get("mn", 15))))

    print("[6] Lingkup berkas KKTP")
    print("      1. Semua semester aktif kelas ini (1 berkas per semester)")
    print("      2. Satu semester saja")
    print("      3. Satu Elemen/CP saja")
    p = tanya("    Pilih nomor", "1")
    semester, elemen_no = None, None
    if p == "2" or p == "3":
        print("    Semester yang tersedia:")
        for a in semester_aktif(fase, kelas):
            print("      \u2022 %d \u2014 %s" % (a[0], a[1]))
        semester = tanya("    Isikan nomor semester atau tulis ganjil/genap",
                         str(semester_aktif(fase, kelas)[0][0]))
    lingkup = {"2": "semester", "3": "elemen"}.get(p, "tahun")
    if p == "3":
        pra = susun_rencana(s["nama_asli"], jp, kelas=kelas, fase=fase, mg=mg,
                            mn=mn, jpp=jpp)
        sumber = detail_aktif(pra, semester)
        print("    Elemen/CP pada semester tersebut:")
        for d in sumber:
            print("      %d. %s" % (d["urut_kelas"], topik_utama(d["elemen"])))
            print("         %d JP | %d pertemuan | %d Tujuan Pembelajaran"
                  % (d["jp"], d["tm"], len(daftar_tp([d]))))
        elemen_no = int(tanya("    Pilih nomor Elemen/CP",
                              str(sumber[0]["urut_kelas"])))

    print("[7] Identitas dokumen")
    sekolah = tanya("    Satuan Pendidikan", bawaan.get("sekolah", "SMKS PGRI 2 Jambi"))
    rombel = tanya("    Kelas yang ditulis (mis. X TSM 1)", bawaan.get("rombel", kelas))
    konsentrasi = tanya("    Konsentrasi Keahlian",
                        bawaan.get("konsentrasi", "Teknik Sepeda Motor"))
    tahun = tanya("    Tahun Pelajaran", bawaan.get("tahun", "2026/2027"))
    kota = tanya("    Kota/kabupaten", bawaan.get("kota", "Jambi"))

    print("[8] Guru Mata Pelajaran")
    print("    Kepala Sekolah sudah tetap: %s (%s)" % (KEPALA_NAMA, KEPALA_NPA))
    penyusun = tanya("    Nama/Penyusun", bawaan.get("penyusun", ""))
    npa = tanya("    NPA", bawaan.get("npa", ""))

    print("")
    print("-" * 74)
    print("Memproses...")
    generate_kktp(s["nama_asli"], jp, kelas=kelas, fase=fase, mg=mg, mn=mn,
                  jpp=jpp, lingkup=lingkup, semester=semester, elemen=elemen_no,
                  sekolah=sekolah, tahun=tahun, penyusun=penyusun, npa=npa,
                  kota=kota, rombel=rombel, konsentrasi=konsentrasi)


# ============================================================================
# 6. CLI
# ============================================================================


def main():
    ap = argparse.ArgumentParser(description="Generator KKTP Kurikulum Nasional 2025")
    ap.add_argument("--form", action="store_true", help="pengisian lewat form tanya-jawab")
    ap.add_argument("--mapel")
    ap.add_argument("--jp", type=int, default=2)
    ap.add_argument("--jpp", type=int, default=None)
    ap.add_argument("--kelas", default="X")
    ap.add_argument("--fase", choices=list("ABCDEF"))
    ap.add_argument("--mg", type=int, default=22)
    ap.add_argument("--mn", type=int, default=15)
    ap.add_argument("--menit", type=int, default=45)
    ap.add_argument("--lingkup", default="semester", help="tahun | semester | elemen")
    ap.add_argument("--semester")
    ap.add_argument("--elemen", type=int)
    ap.add_argument("--sekolah", default="SMKS PGRI 2 Jambi")
    ap.add_argument("--tahun", default="2026/2027")
    ap.add_argument("--penyusun", default=None)
    ap.add_argument("--npa", default=None)
    ap.add_argument("--kota", default="Jambi")
    ap.add_argument("--rombel", default=None)
    ap.add_argument("--konsentrasi", default="Teknik Sepeda Motor")
    ap.add_argument("--elemen-kelas11", dest="elemen_kelas", type=int, default=None)
    ap.add_argument("--out-dir", dest="out_dir", default=None)
    ap.add_argument("--list", dest="cari", help="cari nama mata pelajaran")
    a = ap.parse_args()

    if a.cari:
        for s in cari_mapel(load_db(), a.cari)[:25]:
            print("  %-60s Lampiran %s, %s" % (s["nama_asli"], s["lampiran"], s["kode"]))
        return
    if a.form or not a.mapel:
        mode_form()
        return
    generate_kktp(a.mapel, a.jp, kelas=a.kelas, fase=a.fase, mg=a.mg, mn=a.mn,
                  menit=a.menit, jpp=a.jpp, lingkup=a.lingkup, semester=a.semester,
                  elemen=a.elemen, sekolah=a.sekolah, tahun=a.tahun,
                  penyusun=a.penyusun, npa=a.npa, kota=a.kota, rombel=a.rombel,
                  konsentrasi=a.konsentrasi, elemen_kelas=a.elemen_kelas,
                  out_dir=a.out_dir)


if __name__ == "__main__":
    main()
